﻿#include "ais_curve.h"
#include "ais_point.h"
#include "ais_vectorcloud.h"
#include "kernel/transform.h"
#include "topo/topo_edge.h"

CAGD::AIS_Curve::AIS_Curve(Handle(GeomCurve) curve, bool pure) : AIS_Curve(Handle(TopoEdge)(new TopoEdge(curve)), pure)
{
}

CAGD::AIS_Curve::AIS_Curve(Handle(TopoEdge) edge, bool pure) : m_edge(edge)
{
    // 设置属性
    m_info.size = 100;

    // 非纯曲线才构造子节点
    if (!pure)
    {
        // 创建子节点包围盒
        auto box = Handle(AIS_Box)(new AIS_Box);
        AddChild(box);
        box->UpdateArray();
        m_context.CreateObject(box);

        // 创建质心点，孤立质心点
        m_info.centroid = box->GetBBox().center;
        m_info._centroid = m_info.centroid;
        Handle(GeomPoint) center(new GeomPoint(&m_info.centroid));
        Handle(AIS_Point) c(new AIS_Point(center));
        auto &info = c->GetInfo();
        if (m_context.GetInfo().viewMode != ViewMode::CONTROL)
            info.status = AIS_Status::HIDDEN;
        info.smooth = true;
        info.psize = 10;

        m_context.CreateObject(c);

        // 引用控制点
        auto ref = m_edge->Geom()->MakeReference();
        for (auto P : ref)
        {
            // 每个点都创建，这里传入指针，因此直接包含了引用
            Handle(GeomPoint) PRef(new GeomPoint(P));
            Handle(AIS_Point) Q(new AIS_Point(PRef));
            if (m_context.GetInfo().viewMode != ViewMode::CONTROL)
                Q->GetInfo().status = AIS_Status::HIDDEN;

            // 插入节点
            AddChild(Q);
            m_context.CreateObject(Q);
        }

        // 法向信息
        Handle(AIS_VectorCloud) cloud(new AIS_VectorCloud);
        AddChild(cloud);
        cloud->UpdateArray();
        if (m_context.GetInfo().viewMode != ViewMode::INFO)
            cloud->GetInfo().status = AIS_Status::HIDDEN;
        m_context.CreateObject(cloud);
    }
}

bool CAGD::AIS_Curve::MoveTo(Point pos)
{
    // 隐藏状态不交互，不活跃状态不交互
    if (m_info.status == AIS_Status::HIDDEN || m_info.active == false)
        return false;

    // 临时记录
    bool hang = false;
    auto tmp = m_info.status;
    m_info.status = AIS_Status::NONE;

    auto box = dynamic_cast<AIS_Box *>(GetChild(AIS_Type::BOX));
    if (box->Collision(pos))
    {
        float z1 = 0.8;
        auto &context = m_context;
        auto invModel = Transform::Inverted(m_info.modelMat);
        BPnt q1 = Transform::Perform(invModel, context.GetSpacePoint(pos, z1));
        BPnt q2 = Transform::Perform(invModel, context.GetInfo().viewPos);

        std::vector<BPnt> Poles = GeomCurve::UniformPointSample(m_edge->Geom(), 100);
        for (int i = 1; i < Poles.size(); i++)
        {
            // 计算点到直线的距离
            BVec v = (q2 - q1).Normalized();
            BVec b_a = Poles[i - 1] - Poles[i];

            auto f = [=](double t) -> double {
                BPnt P = Poles[i] * (1 - t) + Poles[i - 1] * t;
                return ((P - q1) % v).Modulus();
            };

            // 计算线段上距离直线最近的点的距离
            double d = 0, t = 0;
            BVec c = b_a - v * (v * b_a);
            if (c.Modulus() < FLT_MIN)
                d = f(0);
            else
            {
                double t = (q1 - Poles[i]) * c / (b_a * c);
                if (t >= 0 && t <= 1)
                    d = f(t);
                else
                    d = std::min(f(0), f(1));
            }

            // 计算点到镜头的距离，距离越远，条件越宽松
            double dc = Poles[i].Distance(context.GetInfo().viewPos);

            // 距离足够小即可
            if (d < dc / 200)
            {
                hang = true;
                if (tmp != AIS_Status::TOUCH)
                    m_info.status = AIS_Status::HANG;
                else
                    m_info.status = tmp;

                float d1, d2;
                context.GetScreenPoint(Poles[i - 1], d1);
                context.GetScreenPoint(Poles[i], d2);

                // 计算深度
                SetDepth(std::min(d1, d2));
                break;
            }
        }
    }
    return hang;
}

void CAGD::AIS_Curve::UpdateInfo()
{
    // 重置纹理
    m_info.diffuseTex = 0;
    m_info.modelMat = Transform::Translate(m_info.centroid - m_info._centroid);

    // 设置不活跃状态的颜色
    if (m_info.active == false)
        m_info.color = {0.3, 0.3, 0.3, 0.3};
    else if (m_info.status == AIS_Status::NONE)
        m_info.color = {1, 1, 0, 1};
    else if (m_info.status == AIS_Status::HANG)
        m_info.color = {0, 0, 1, 1};
    else if (m_info.status == AIS_Status::TOUCH)
        m_info.diffuseTex = TEXTURE::DASH;
}

CAGD::AIS_Type CAGD::AIS_Curve::GetType() const
{
    return AIS_Type::CURVE;
}

Handle(CAGD::GeomCurve) CAGD::AIS_Curve::GetCurve() const
{
    return m_edge->Geom();
}

Handle(CAGD::TopoEdge) CAGD::AIS_Curve::GetEdge() const
{
    return m_edge;
}
